package cn.dengta.webapp.trade.service;

import java.util.*;
import java.util.stream.Collectors;
import javax.annotation.Nonnull;

import cn.dengta.common.model.TimeInterval;
import cn.dengta.common.web.Page;
import cn.dengta.webapp.base.service.BaseServiceImpl;
import cn.dengta.webapp.base.util.MybatisUtil;
import cn.dengta.webapp.trade.dao.UserCoinLogDao;
import cn.dengta.webapp.trade.dto.UserCoinLogSumDTO;
import cn.dengta.webapp.trade.dto.UserCoinSumDTO;
import cn.dengta.webapp.trade.entity.UserCoinLog;
import cn.dengta.webapp.trade.form.UserCoinLogQuery;
import cn.dengta.webapp.trade.model.TradeType;
import cn.dengta.webapp.user.entity.User;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import me.codeplayer.util.*;
import org.springframework.stereotype.Service;

import static cn.dengta.webapp.base.entity.BaseEntity.ID;
import static cn.dengta.webapp.base.entity.TimeBasedEntity.ADD_TIME;
import static cn.dengta.webapp.trade.entity.UserCoinLog.*;
import static cn.dengta.webapp.trade.entity.UserIntegralLog.FLOW;
import static cn.dengta.webapp.trade.entity.UserIntegralLog.TRADE_TYPE;

/**
 * 钻石流水记录表 服务实现类
 *
 * @author yuqidi
 * @since 2022-03-12
 */
@Service
public class UserCoinLogService extends BaseServiceImpl<UserCoinLog, UserCoinLogDao, Long> {

	public Page<UserCoinLog> findPage(Page<UserCoinLog> page, UserCoinLog input, TimeInterval addTimeInterval) {
		QueryWrapper<UserCoinLog> wrapper = popWrapper(X.map(input, UserCoinLog::getUserId), X.map(input, UserCoinLog::getOrderNo), X.map(input, UserCoinLog::getFlow),
				X.map(input, UserCoinLog::getSide), X.map(input, UserCoinLog::getAssocType), X.map(input, UserCoinLog::getAssocId), X.map(input, UserCoinLog::getTradeType), null, addTimeInterval, null);
		wrapper.orderByDesc(ID);
		return baseDao.selectPage(page, wrapper);
	}

	public Page<UserCoinLog> findUserPage(Page<UserCoinLog> page, UserCoinLog input, TimeInterval addTimeInterval, TradeType... tradeTypes) {
		QueryWrapper<UserCoinLog> wrapper = new QueryWrapper<>();
		final String prefix = "log.";
		if (input != null) {
			wrapper.eq(input.getFlow() != null, prefix + FLOW, input.getFlow());
			wrapper.eq(StringUtil.notEmpty(input.getTradeType()), prefix + TRADE_TYPE, input.getTradeType());
			User user = input.getUser();
			if (user != null) {
				wrapper.eq(user.getId() != null, "u.id", user.getId());
				wrapper.like(StringUtil.notEmpty(user.getNickname()), "u.nickname", user.getNickname());
				wrapper.eq(user.getAgentId() != null, "u." + User.AGENT_ID, user.getAgentId());
			}
		}
		MybatisUtil.wrapperInOrEq(wrapper, prefix + TRADE_TYPE, tradeTypes);
		MybatisUtil.wrapperInterval(wrapper, prefix + ADD_TIME, addTimeInterval);
		wrapper.orderByDesc(prefix + ID);
		return baseDao.findPage(page, wrapper);
	}

	public List<UserCoinLog> find(Long userId, Integer flow, Integer side, String assocType, Long assocId, TradeType[] tradeTypes, TimeInterval addTimeInterval) {
		return selectList(popWrapper(userId, null, flow, side, assocType, assocId, null, null, addTimeInterval, tradeTypes));
	}

	public List<UserCoinLog> find(Long userId, String orderNO, TimeInterval addTimeInterval, Integer handleStatus, TradeType... tradeTypes) {
		return selectList(popWrapper(userId, orderNO, null, null, null, null, null, handleStatus, addTimeInterval, tradeTypes));
	}

	public int count(Long userId, String orderNO, TimeInterval addTimeInterval, TradeType... tradeTypes) {
		return NumberUtil.getInt(count(popWrapper(userId, orderNO, null, null, null, null, null, null, addTimeInterval, tradeTypes)), 0);
	}

	/***
	 * 查询指定用户、指定交易时间段、指定交易类型(可变参数)的交易数据键/值对(交易类型/交易金额)即可
	 */
	public List<UserCoinLogSumDTO> getSumOfTradeAmountGroupByType(Long[] userIds, Long[] toUserIds, Integer flow, TimeInterval addTimeInterval, @Nonnull TradeType... tradeTypes) {
		return baseDao.getSumOfTradeAmountGroupByType(userIds, toUserIds, flow, addTimeInterval, tradeTypes);
	}

	public List<UserCoinLogSumDTO> findSumOfInfo(Long[] userIds, Integer flow, TimeInterval addTimeInterval, String groupAttr, String selectKey, @Nonnull TradeType... tradeTypes) {
		UserCoinLogQuery query = new UserCoinLogQuery()
				.setFlow(flow);
		query.userIds = userIds;
		query.groupAttr = groupAttr;
		query.selectKey = selectKey;
		return baseDao.findSumOfInfo(query, addTimeInterval, tradeTypes);
	}

	/**
	 * 统计数量
	 *
	 * @param flow 资金流向：1=收入；0=不变；-1=支出
	 * @param side 交易方：1=from；2=to
	 */
	public int count(Long userId, String orderNO, Integer flow, Integer side, String assocType, Long assocId, TimeInterval addTimeInterval, TradeType... tradeTypes) {
		return NumberUtil.getInt(count(popWrapper(userId, orderNO, flow, side, assocType, assocId, null, null, addTimeInterval, tradeTypes)), 0);
	}

	private QueryWrapper<UserCoinLog> popWrapper(Long userId, String orderNO, Integer flow, Integer side, String assocType, Long assocId, String tradeType, Integer handleStatus, TimeInterval addTimeInterval, TradeType[] tradeTypes) {
		QueryWrapper<UserCoinLog> wrapper = new QueryWrapper<>();
		wrapper.eq(userId != null, USER_ID, userId)
				.eq(flow != null, FLOW, flow)
				.eq(side != null, SIDE, side)
				.eq(handleStatus != null, HANDLE_STATUS, handleStatus)
				.like(StringUtil.notEmpty(orderNO), ORDER_NO, orderNO)
				.eq(assocId != null, ASSOC_ID, assocId)
				.eq(StringUtil.notEmpty(assocType), ASSOC_TYPE, assocType)
				.eq(StringUtil.notEmpty(tradeType), TRADE_TYPE, tradeType);
		MybatisUtil.wrapperInOrEq(wrapper, TRADE_TYPE, tradeTypes);
		MybatisUtil.wrapperInterval(wrapper, ADD_TIME, addTimeInterval);
		return wrapper;
	}

	public int updateHandleStatus(Long id) {
		return baseDao.updateHandleStatus(id);
	}

	public Map<Long, Integer> findCoinByIds(Collection<Long> ids) {
		if (!X.isValid(ids)) {
			return Collections.emptyMap();
		}
		QueryWrapper<UserCoinLog> wrapper = new QueryWrapper<>();
		wrapper.select(ID, TRADE_AMOUNT);
		wrapper.in(ID, ids);
		return selectList(wrapper).stream().collect(Collectors.toMap(UserCoinLog::getId, UserCoinLog::getTradeAmount, (a, b) -> a));
	}

	public UserCoinLogSumDTO getSumOfTodayCoin(Long userId, Long toUserId, TimeInterval timeInterval, TradeType tradeType) {
		return baseDao.getSumOfTodayCoin(userId, toUserId, timeInterval, tradeType);
	}

	public UserCoinLogSumDTO getSumOfYesterdayCoin(Long userId, TimeInterval timeInterval) {
		return baseDao.getSumOfYesterdayCoin(userId, timeInterval);
	}

	public List<UserCoinSumDTO> coinDetailExport(Long userId) {
		return baseDao.coinDetailExport(userId);
	}

}
